package com.jiangyg.mall.db.hibernate.transform;

import com.jiangyg.mall.core.utils.HumpUtils;
import com.jiangyg.mall.db.SQLUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.HibernateException;
import org.hibernate.transform.AliasedTupleSubsetResultTransformer;
import org.springframework.beans.BeanUtils;

import java.beans.PropertyDescriptor;
import java.sql.Blob;
import java.sql.Clob;

public class AliasToBeanResultTransformer<T> extends AliasedTupleSubsetResultTransformer {

    private static final long serialVersionUID = 6246860007202253426L;

    private final Class<T> clazz;

    public AliasToBeanResultTransformer(Class<T> clazz) {
        this.clazz = clazz;
    }

    @Override
    public Object transformTuple(Object[] tuple, String[] aliases) {
        String alias = null;
        Class<?> valueClazz = null;
        Class<?> entityClazz = null;
        try {
            Object value;
            final T result = clazz.newInstance();
            for (int i = 0; i < tuple.length; i++) {
                alias = aliases[i];
                // 列名为空不处理
                if (alias == null) {
                    continue;
                }
                value = tuple[i];
                // 值为空则跳过，不处理
                if (value == null) {
                    continue;
                }
                // 列名转驼峰
                alias = HumpUtils.underlineToCamel(alias.toLowerCase());
                // 类型判断及转换
                final PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(clazz, alias);
                // 查询出来的列在bean没有，不处理
                if (descriptor == null) {
                    continue;
                }
                valueClazz = value.getClass();
                entityClazz = descriptor.getPropertyType();
                // 从Character转String
                if (entityClazz == String.class && valueClazz == Character.class) {
                    value = String.valueOf(value);
                }
                // 从Clob转String
                if (entityClazz == String.class && Clob.class.isAssignableFrom(valueClazz)) {
                    value = SQLUtils.clobToString((Clob) value);
                }
                // 从Blob转String
                if (entityClazz == String.class && Blob.class.isAssignableFrom(valueClazz)) {
                    final Blob b = (Blob) value;
                    value = new String(b.getBytes(1, (int) b.length()));
                }
                // 从byte[]转String
                if (entityClazz == String.class && value instanceof byte[]) {
                    value = new String((byte[]) value);
                }
                // 从Number转String
                if (entityClazz == String.class && Number.class.isAssignableFrom(valueClazz)) {
                    value = String.valueOf(value);
                }
                // 其他情况
                descriptor.getWriteMethod().invoke(result, value);
            }
            return result;
        } catch (Exception ex) {
            if (StringUtils.isBlank(alias)) {
                throw new HibernateException("实例化[" + clazz.getName() + "]失败，确认下类是否有默认构造器", ex);
            }
            throw new HibernateException("实例化[" + clazz.getName() + "]失败，字段[" + alias + "]从[" + valueClazz + "]转换[" + entityClazz + "]出现异常", ex);
        }
    }

    @Override
    public boolean isTransformedValueATupleElement(String[] aliases, int tupleLength) {
        return false;
    }

}
